#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_adc.h"
#include "misc.h"

#include "common.h"
#include "dac.h"

// ADC1通道0（PA0）
void adc_gpio_init()
{
    GPIO_InitTypeDef adc_ch;
    // 使能APB2总线下面GPIOA的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    adc_ch.GPIO_Pin = GPIO_Pin_0;     // 指定引脚号为0
    adc_ch.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入
    // 初始化ADC IO
    GPIO_Init(GPIOA, &adc_ch);
}

void adc_nvic_init()
{
    NVIC_InitTypeDef adc;
    // 组2：4个抢占优先级，4个执行优先级，最均衡的一个
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    // 指定中断号，根据中断号，可以找到对应的中断地址，中断地址里面有中断函数
    // 这里ADC1_2_IRQn对应的中断函数（地址）就是指向ADC1_2_IRQHandler
    adc.NVIC_IRQChannel = ADC1_2_IRQn;
    // 抢占优先级为1
    adc.NVIC_IRQChannelPreemptionPriority = 1;
    // 执行优先级也是1，4位优先级bit：0101
    adc.NVIC_IRQChannelSubPriority = 1;
    // 使能NVIC的中断通道
    // 在stm32中有外部中断和定时器中断，这里是使能外部中断里面的ADC1_2_IRQn
    // 即可以响应ADC1_2_IRQn中断，即触发ADC1_2_IRQHandler函数
    adc.NVIC_IRQChannelCmd = ENABLE;

    // 这一步重中之重，上面一堆配置都只是配置，真正生效，写到寄存器里面都是在
    // init函数里面实现的
    NVIC_Init(&adc);
}

void adc_init(MODE mode)
{
    ADC_InitTypeDef ADC_InitStruct;
    // APB2（高速时钟）下面的ADC1时钟使能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    adc_gpio_init();
    // stm32F103C8，只有一个ADC通道，所以只能选择独立模式
    // 在高级的stm32中才会有多个ADC通道，此时才有规则组，注入组概念
    // 
    ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
    // 只有多通道的时候才会考虑使用扫描模式，所谓扫描就是逐个通道进行轮询扫描
    // scan其实可以联想到c语言里面的scanf，其实就是只轮询指定通道是否有数据
    // 这里我们使用的独立模式即单通道，所以不适用
    ADC_InitStruct.ADC_ScanConvMode = DISABLE;
    ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; // 启动持续转换模式
    // 不使用外部触发，而是采用直接启动
    ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStruct.ADC_NbrOfChannel = 1; // 通道组设置，设置范围1~16

    ADC_Init(ADC1, &ADC_InitStruct);
    // 在system_init里面已经配置了默认时钟，72MHz；这里是8倍分频，所以是9MHz
    // 只要大小不超过14MHz即可
    RCC_ADCCLKConfig(RCC_PCLK2_Div8);                                           // ADC时钟配置
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); // 采样周期配置
    ADC_Cmd(ADC1, ENABLE);                                                      // ADC时钟配置
    ADC_ResetCalibration(ADC1);                                                 // 复位校准器
    while (ADC_GetResetCalibrationStatus(ADC1))
        ;
    // ADC开始校准
    ADC_StartCalibration(ADC1);
    // 等待校准完成
    while (ADC_GetCalibrationStatus(ADC1))
        ;

    ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 启动软件直接触发ADC
    if (INTERRUPT == mode)
    {
        ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
        adc_nvic_init();
    }
}

float adc_vol_get(u16 adc_value)
{
    // 每次都要调用start函数
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    return (float)adc_value / 4096 * 3.3; // 2^12 = 4096
}

u16 adc1_value = 0;
float adc1_vol = 0.0;

void ADC1_2_IRQHandler()
{
    // SET，代表转换结束
    if (ADC_GetITStatus(ADC1, ADC_IT_EOC) == SET)
    {
        // 读取到ADC转换值
        // TODO adc1_value的取值范围是0~2^12
        adc1_value = ADC_GetConversionValue(ADC1);
    }

    ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
}